package com.java.volatiledemo;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author wangning
 * @date 2023/5/11 10:21
 * 1.验证volatile可见性，
 * 1.1 假如 int number = 0; number变量之前根本没有添加volatile关键字修饰
 * 1.2 添加了volatile，可以解决可见性问题
 * 2. 验证volatile不保证原子性
 * 2.1 原子性是什么意思？
 *     不可分割，完整性，即某个线程正在做某个业务的时候，中间不可以加塞或者被分割，需要整体完整
 *     要么同时成功，要么同时失败
 * 2.2 volatile不保证原子性的案例演示
 * 2.3 为什么不能保证原子性
 * 2.4 如何解决原子性
 *     加sync
 *     直接使用功能juc下的Atomic
 *
 */
public class VolatileDemo1 {
    public static void main(String[] args) {
//        seeOkByVolatile();
        MyData myData = new MyData();
        for (int i = 0; i < 20; i++) {
            new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    myData.addPlusPlus();
                    myData.addPlusPlusPro();
                }
            }, String.valueOf(i)).start();
        }

        //需要等待上面20个线程执行完后，再用main线程去的最终的结果值是多少？
        //暂停一会
//        try {
//            TimeUnit.SECONDS.sleep(5);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
        while (Thread.activeCount() > 2) {
            Thread.yield();
        }
        System.out.println(Thread.currentThread().getName() + "\t finally number value：" + myData.number);
        System.out.println(Thread.currentThread().getName() + "\t finally number value：" + myData.atomicInteger);

    }

    //volatile可以保证可见性，及时通知其它线程，住物理内存的值已经被修改
    private static void seeOkByVolatile() {
        MyData myData = new MyData();
        //第一个线程
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "\t come in");
            try {
                TimeUnit.SECONDS.sleep(3);
                myData.addTo60();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "\t update number value：" + myData.number);
        },"AAA").start();
        //第二个线程，主线程
        while (myData.number == 0) {
            //main线程一直在这里循环等待，主要不是0，就停止
        }
        System.out.println(Thread.currentThread().getName() + "\t mission is over number value：" + myData.number);
    }
}
class MyData {
//    int number = 0;
    volatile int number = 0;
    public void addTo60() {
        this.number = 60;
    }

    public void addPlusPlus() {
        number++;
    }

    AtomicInteger atomicInteger = new AtomicInteger();
    public void addPlusPlusPro() {
        atomicInteger.getAndIncrement();
    }
}

